🎯 6 Bài Tập JavaScript Thực Hành

Luyện tập các kỹ năng JavaScript từ cơ bản đến nâng cao

Cách thức: Mỗi bài có 4 hàm nhỏ, các hàm có thể gọi lẫn nhau

Mật khẩu xem đáp án: 123ez123

Bài Tập 1: Quản Lý Điểm Học Sinh

🎯 Mục tiêu

Tạo hệ thống quản lý điểm số học sinh với các chức năng: tính điểm trung bình, phân loại học lực, và tạo báo cáo.

📥 Dữ liệu mẫu

const students = [
  { name: "Nguyen Van A", math: 8, physics: 7, chemistry: 9 },
  { name: "Le Thi B", math: 6, physics: 7, chemistry: 8 },
  { name: "Tran Van C", math: 9, physics: 8, chemistry: 8 },
  { name: "Pham Thi D", math: 5, physics: 6, chemistry: 7 }
];

� Các hàm cần viết

🔧 Hàm 1: calculateAverage(student)

Nhiệm vụ: Tính điểm trung bình 3 môn của 1 học sinh

Input: Object student có các thuộc tính math, physics, chemistry

Output: Number - điểm trung bình (làm tròn 1 chữ số thập phân)

Ví dụ:

calculateAverage({ name: "An", math: 8, physics: 7, chemistry: 9 })
// Trả về: 8.0

🔧 Hàm 2: classifyStudent(average)

Nhiệm vụ: Phân loại học lực dựa trên điểm trung bình

Input: Number average (điểm trung bình)

Output: String - "Giỏi" (≥8), "Khá" (≥6.5), "Trung bình" (≥5), "Yếu" (<5)

Ví dụ:

classifyStudent(8.0)  // Trả về: "Giỏi"
classifyStudent(7.0)  // Trả về: "Khá"

🔧 Hàm 3: processAllStudents(students)

Nhiệm vụ: Xử lý toàn bộ danh sách học sinh (sử dụng hàm 1 và 2)

Input: Array students

Output: Array - mỗi phần tử chứa {name, average, classification}

Ví dụ:

// Trả về:
[
  { name: "Nguyen Van A", average: 8.0, classification: "Giỏi" },
  { name: "Le Thi B", average: 7.0, classification: "Khá" }
]

🔧 Hàm 4: generateReport(processedStudents)

Nhiệm vụ: Tạo báo cáo thống kê tổng hợp

Input: Array processedStudents (từ hàm 3)

Output: String - báo cáo có định dạng đẹp

Ví dụ:

// Trả về:
"=== BÁO CÁO HỌC TẬP ===
Tổng số học sinh: 4
Điểm trung bình chung: 7.2
- Học sinh giỏi: 1 (25%)
- Học sinh khá: 2 (50%)
- Học sinh trung bình: 1 (25%)"

🔓 Xem đáp án

Nhập mật khẩu để xem lời giải chi tiết:

💡 Lời giải chi tiết

Hàm 1: calculateAverage(student)

function calculateAverage(student) {
  const total = student.math + student.physics + student.chemistry;
  const average = total / 3;
  return Math.round(average * 10) / 10; // Làm tròn 1 chữ số thập phân
}

Hàm 2: classifyStudent(average)

function classifyStudent(average) {
  if (average >= 8) return "Giỏi";
  if (average >= 6.5) return "Khá";
  if (average >= 5) return "Trung bình";
  return "Yếu";
}

Hàm 3: processAllStudents(students)

function processAllStudents(students) {
  return students.map(student => {
    const average = calculateAverage(student);
    const classification = classifyStudent(average);
    return {
      name: student.name,
      average: average,
      classification: classification
    };
  });
}

Hàm 4: generateReport(processedStudents)

function generateReport(processedStudents) {
  const total = processedStudents.length;
  const totalAverage = processedStudents.reduce((sum, student) => sum + student.average, 0) / total;
  
  // Đếm theo từng loại
  const counts = {
    "Giỏi": processedStudents.filter(s => s.classification === "Giỏi").length,
    "Khá": processedStudents.filter(s => s.classification === "Khá").length,
    "Trung bình": processedStudents.filter(s => s.classification === "Trung bình").length,
    "Yếu": processedStudents.filter(s => s.classification === "Yếu").length
  };
  
  return `=== BÁO CÁO HỌC TẬP ===
Tổng số học sinh: ${total}
Điểm trung bình chung: ${totalAverage.toFixed(1)}
- Học sinh giỏi: ${counts["Giỏi"]} (${(counts["Giỏi"]/total*100).toFixed(0)}%)
- Học sinh khá: ${counts["Khá"]} (${(counts["Khá"]/total*100).toFixed(0)}%)
- Học sinh trung bình: ${counts["Trung bình"]} (${(counts["Trung bình"]/total*100).toFixed(0)}%)
- Học sinh yếu: ${counts["Yếu"]} (${(counts["Yếu"]/total*100).toFixed(0)}%)`;
}

Cách sử dụng:

// Test với dữ liệu mẫu
const students = [
  { name: "Nguyen Van A", math: 8, physics: 7, chemistry: 9 },
  { name: "Le Thi B", math: 6, physics: 7, chemistry: 8 },
  { name: "Tran Van C", math: 9, physics: 8, chemistry: 8 },
  { name: "Pham Thi D", math: 5, physics: 6, chemistry: 7 }
];

const processed = processAllStudents(students);
console.log(processed);
console.log(generateReport(processed));

Bài Tập 2: Quản Lý Sản Phẩm Cửa Hàng

🎯 Mục tiêu

Tạo hệ thống quản lý sản phẩm với các chức năng: tìm kiếm, lọc theo giá, tính tổng tiền giỏ hàng.

📥 Dữ liệu mẫu

const products = [
  { id: 1, name: "Laptop Dell", price: 15000000, category: "Electronics", stock: 5 },
  { id: 2, name: "iPhone 15", price: 25000000, category: "Electronics", stock: 3 },
  { id: 3, name: "Áo thun", price: 200000, category: "Fashion", stock: 20 },
  { id: 4, name: "Giày Nike", price: 3000000, category: "Fashion", stock: 8 }
];

const cart = [
  { productId: 1, quantity: 1 },
  { productId: 3, quantity: 2 }
];

� Các hàm cần viết

🔧 Hàm 1: findProductById(products, id)

Nhiệm vụ: Tìm sản phẩm theo ID

Input: Array products, Number id

Output: Object product hoặc null nếu không tìm thấy

Ví dụ:

findProductById(products, 1)
// Trả về: { id: 1, name: "Laptop Dell", price: 15000000, category: "Electronics", stock: 5 }

🔧 Hàm 2: filterProductsByPrice(products, minPrice, maxPrice)

Nhiệm vụ: Lọc sản phẩm theo khoảng giá

Input: Array products, Number minPrice, Number maxPrice

Output: Array các sản phẩm có giá trong khoảng [minPrice, maxPrice]

Ví dụ:

filterProductsByPrice(products, 1000000, 20000000)
// Trả về: [Laptop Dell, iPhone 15, Giày Nike]

🔧 Hàm 3: calculateCartTotal(products, cart)

Nhiệm vụ: Tính tổng tiền giỏ hàng (sử dụng hàm 1)

Input: Array products, Array cart

Array cart là gì: Mảng chứa các sản phẩm trong giỏ hàng

// Ví dụ cart:
const cart = [
  { productId: 1, quantity: 1 },    // Mua 1 Laptop Dell
  { productId: 3, quantity: 2 }     // Mua 2 Áo thun
];

Output: Object {items: [], total: number, tax: number, finalTotal: number}

Công thức thuế: VAT = 10% = tổng tiền × 0.1

Ví dụ tính toán:

calculateCartTotal(products, cart)
// Tính toán:
// Item 1: Laptop Dell (1 × 15,000,000đ) = 15,000,000đ
// Item 2: Áo thun (2 × 200,000đ) = 400,000đ
// Tổng tiền: 15,000,000 + 400,000 = 15,400,000đ
// Thuế VAT: 15,400,000 × 0.1 = 1,540,000đ
// Tổng cộng: 15,400,000 + 1,540,000 = 16,940,000đ

// Trả về:
{
  items: [
    { name: "Laptop Dell", quantity: 1, price: 15000000, subtotal: 15000000 },
    { name: "Áo thun", quantity: 2, price: 200000, subtotal: 400000 }
  ],
  total: 15400000,      // Tổng tiền trước thuế
  tax: 1540000,         // Thuế VAT 10%
  finalTotal: 16940000  // Tổng tiền sau thuế
}

🔧 Hàm 4: generateInvoice(cartResult)

Nhiệm vụ: Tạo hóa đơn từ kết quả hàm 3

Input: Object cartResult (từ hàm calculateCartTotal)

Output: String - hóa đơn có định dạng đẹp

Ví dụ:

// Trả về:
"========== HÓA ĐƠN ==========
Laptop Dell       x1    15,000,000đ
Áo thun          x2       400,000đ
----------------------------------
Tạm tính:              15,400,000đ
Thuế VAT (10%):         1,540,000đ
----------------------------------
TỔNG CỘNG:             16,940,000đ"

🔓 Xem đáp án

💡 Lời giải chi tiết

Hàm 1: findProductById(products, id)

function findProductById(products, id) {
  return products.find(product => product.id === id) || null;
}

Hàm 2: filterProductsByPrice(products, minPrice, maxPrice)

function filterProductsByPrice(products, minPrice, maxPrice) {
  return products.filter(product => 
    product.price >= minPrice && product.price <= maxPrice
  );
}

Hàm 3: calculateCartTotal(products, cart)

function calculateCartTotal(products, cart) {
  const items = cart.map(cartItem => {
    const product = findProductById(products, cartItem.productId);
    if (!product) return null;
    
    const subtotal = product.price * cartItem.quantity;
    return {
      name: product.name,
      quantity: cartItem.quantity,
      price: product.price,
      subtotal: subtotal
    };
  }).filter(item => item !== null);
  
  const total = items.reduce((sum, item) => sum + item.subtotal, 0);
  const tax = total * 0.1; // 10% VAT
  const finalTotal = total + tax;
  
  return {
    items: items,
    total: total,
    tax: tax,
    finalTotal: finalTotal
  };
}

Hàm 4: generateInvoice(cartResult)

function generateInvoice(cartResult) {
  let invoice = "========== HÓA ĐƠN ==========\n";
  
  // Liệt kê các sản phẩm
  cartResult.items.forEach(item => {
    const name = item.name.padEnd(20);
    const quantity = `x${item.quantity}`.padEnd(8);
    const price = `${item.subtotal.toLocaleString()}đ`;
    invoice += `${name} ${quantity} ${price}\n`;
  });
  
  invoice += "----------------------------------\n";
  invoice += `Tạm tính:              ${cartResult.total.toLocaleString()}đ\n`;
  invoice += `Thuế VAT (10%):         ${cartResult.tax.toLocaleString()}đ\n`;
  invoice += "----------------------------------\n";
  invoice += `TỔNG CỘNG:             ${cartResult.finalTotal.toLocaleString()}đ`;
  
  return invoice;
}

Cách sử dụng:

// Test với dữ liệu mẫu
const products = [
  { id: 1, name: "Laptop Dell", price: 15000000, category: "Electronics", stock: 5 },
  { id: 2, name: "iPhone 15", price: 25000000, category: "Electronics", stock: 3 },
  { id: 3, name: "Áo thun", price: 200000, category: "Fashion", stock: 20 },
  { id: 4, name: "Giày Nike", price: 3000000, category: "Fashion", stock: 8 }
];

const cart = [
  { productId: 1, quantity: 1 },
  { productId: 3, quantity: 2 }
];

// Test từng hàm
console.log(findProductById(products, 1));
console.log(filterProductsByPrice(products, 1000000, 20000000));

const cartResult = calculateCartTotal(products, cart);
console.log(cartResult);
console.log(generateInvoice(cartResult));

Bài Tập 3: Quản Lý Thư Viện Sách

🎯 Mục tiêu

Tạo hệ thống quản lý thư viện với các chức năng: tìm kiếm sách, mượn/trả sách, thống kê.

📥 Dữ liệu mẫu

const books = [
  { id: 1, title: "JavaScript Guide", author: "John Doe", category: "Programming", available: true, publishYear: 2020 },
  { id: 2, title: "Python Basics", author: "Jane Smith", category: "Programming", available: false, publishYear: 2019 },
  { id: 3, title: "Web Design", author: "Bob Wilson", category: "Design", available: true, publishYear: 2021 },
  { id: 4, title: "Database Systems", author: "Alice Brown", category: "Programming", available: true, publishYear: 2018 }
];

const members = [
  { id: 1, name: "Nguyen Van A", email: "a@email.com", borrowedBooks: [2] },
  { id: 2, name: "Le Thi B", email: "b@email.com", borrowedBooks: [] }
];

📤 Các hàm cần viết

🔧 Hàm 1: findBooksByCategory(books, category)

Nhiệm vụ: Tìm tất cả sách thuộc thể loại được chỉ định

Input: Array books, String category

Output: Array các sách thuộc thể loại đó

Ví dụ:

findBooksByCategory(books, "Programming")
// Trả về: [JavaScript Guide, Python Basics, Database Systems]

🔧 Hàm 2: getAvailableBooks(books)

Nhiệm vụ: Lấy danh sách sách có thể mượn

Input: Array books

Output: Array các sách có available = true

Ví dụ:

getAvailableBooks(books)
// Trả về: [JavaScript Guide, Web Design, Database Systems]

🔧 Hàm 3: borrowBook(books, members, memberId, bookId)

Nhiệm vụ: Xử lý việc mượn sách (sử dụng hàm 1 và 2)

Input: Array books, Array members, Number memberId, Number bookId

Output: Object {success: boolean, message: string, updatedMember: object}

Ví dụ:

borrowBook(books, members, 1, 3)
// Trả về:
{
  success: true,
  message: "Mượn sách thành công",
  updatedMember: { id: 1, name: "Nguyen Van A", borrowedBooks: [2, 3] }
}

🔧 Hàm 4: generateLibraryReport(books, members)

Nhiệm vụ: Tạo báo cáo thống kê thư viện

Input: Array books, Array members

Output: String - báo cáo có định dạng đẹp

Ví dụ:

// Trả về:
"========== BÁO CÁO THƯ VIỆN ==========
Tổng số sách: 4
Sách có sẵn: 3
Sách đã mượn: 1
Tổng thành viên: 2
Thành viên đang mượn: 1
Thể loại phổ biến: Programming (3 sách)"

🔓 Xem đáp án

💡 Lời giải chi tiết

Hàm 1: findBooksByCategory(books, category)

function findBooksByCategory(books, category) {
  return books.filter(book => book.category === category);
}

Hàm 2: getAvailableBooks(books)

function getAvailableBooks(books) {
  return books.filter(book => book.available === true);
}

Hàm 3: borrowBook(books, members, memberId, bookId)

function borrowBook(books, members, memberId, bookId) {
  const member = members.find(m => m.id === memberId);
  const book = books.find(b => b.id === bookId);
  
  if (!member) {
    return { success: false, message: "Thành viên không tồn tại", updatedMember: null };
  }
  
  if (!book) {
    return { success: false, message: "Sách không tồn tại", updatedMember: null };
  }
  
  if (!book.available) {
    return { success: false, message: "Sách đã được mượn", updatedMember: null };
  }
  
  // Cập nhật trạng thái
  book.available = false;
  member.borrowedBooks.push(bookId);
  
  return {
    success: true,
    message: "Mượn sách thành công",
    updatedMember: member
  };
}

Hàm 4: generateLibraryReport(books, members)

function generateLibraryReport(books, members) {
  const totalBooks = books.length;
  const availableBooks = getAvailableBooks(books).length;
  const borrowedBooks = totalBooks - availableBooks;
  const totalMembers = members.length;
  const membersWithBooks = members.filter(m => m.borrowedBooks.length > 0).length;
  
  // Tìm thể loại phổ biến
  const categoryCount = {};
  books.forEach(book => {
    categoryCount[book.category] = (categoryCount[book.category] || 0) + 1;
  });
  
  const popularCategory = Object.keys(categoryCount).reduce((a, b) => 
    categoryCount[a] > categoryCount[b] ? a : b
  );
  
  return `========== BÁO CÁO THƯ VIỆN ==========
Tổng số sách: ${totalBooks}
Sách có sẵn: ${availableBooks}
Sách đã mượn: ${borrowedBooks}
Tổng thành viên: ${totalMembers}
Thành viên đang mượn: ${membersWithBooks}
Thể loại phổ biến: ${popularCategory} (${categoryCount[popularCategory]} sách)`;
}

Cách sử dụng:

// Test với dữ liệu mẫu
const books = [
  { id: 1, title: "JavaScript Guide", author: "John Doe", category: "Programming", available: true, publishYear: 2020 },
  { id: 2, title: "Python Basics", author: "Jane Smith", category: "Programming", available: false, publishYear: 2019 },
  { id: 3, title: "Web Design", author: "Bob Wilson", category: "Design", available: true, publishYear: 2021 },
  { id: 4, title: "Database Systems", author: "Alice Brown", category: "Programming", available: true, publishYear: 2018 }
];

const members = [
  { id: 1, name: "Nguyen Van A", email: "a@email.com", borrowedBooks: [2] },
  { id: 2, name: "Le Thi B", email: "b@email.com", borrowedBooks: [] }
];

// Test từng hàm
console.log(findBooksByCategory(books, "Programming"));
console.log(getAvailableBooks(books));

const borrowResult = borrowBook(books, members, 1, 3);
console.log(borrowResult);
console.log(generateLibraryReport(books, members));

Bài Tập 4: Quản Lý Điểm Thi Học Sinh

🎯 Mục tiêu

Tạo hệ thống quản lý điểm thi với các chức năng: tính điểm trung bình, xếp loại, thống kê lớp học.

📥 Dữ liệu mẫu

const students = [
  { id: 1, name: "Nguyen Van A", class: "10A1", subjects: { math: 8, physics: 7, chemistry: 9 } },
  { id: 2, name: "Le Thi B", class: "10A1", subjects: { math: 6, physics: 8, chemistry: 7 } },
  { id: 3, name: "Tran Van C", class: "10A2", subjects: { math: 9, physics: 8, chemistry: 8 } },
  { id: 4, name: "Pham Thi D", class: "10A1", subjects: { math: 5, physics: 6, chemistry: 7 } }
];

const gradeRules = {
  excellent: 8.5,  // >= 8.5
  good: 7.0,       // >= 7.0
  average: 5.5,    // >= 5.5
  weak: 0          // < 5.5
};

📤 Các hàm cần viết

🔧 Hàm 1: calculateStudentAverage(student)

Nhiệm vụ: Tính điểm trung bình của một học sinh

Input: Object student

Output: Number - điểm trung bình (làm tròn 1 chữ số thập phân)

Ví dụ:

calculateStudentAverage(students[0])
// Trả về: 8.0  (8+7+9)/3 = 8.0

🔧 Hàm 2: classifyStudent(average)

Nhiệm vụ: Xếp loại học sinh dựa trên điểm trung bình

Input: Number average

Output: String - xếp loại ("Giỏi", "Khá", "Trung bình", "Yếu")

Ví dụ:

classifyStudent(8.0)
// Trả về: "Khá"

🔧 Hàm 3: getStudentsByClass(students, className)

Nhiệm vụ: Lọc học sinh theo lớp và tính điểm trung bình (sử dụng hàm 1 và 2)

Input: Array students, String className

Output: Array các học sinh trong lớp với thông tin điểm trung bình và xếp loại

Ví dụ:

getStudentsByClass(students, "10A1")
// Trả về: [
//   { id: 1, name: "Nguyen Van A", class: "10A1", average: 8.0, classification: "Khá" },
//   { id: 2, name: "Le Thi B", class: "10A1", average: 7.0, classification: "Khá" }
// ]

🔧 Hàm 4: generateClassReport(students, className)

Nhiệm vụ: Tạo báo cáo thống kê cho một lớp học

Input: Array students, String className

Output: String - báo cáo thống kê chi tiết

Ví dụ:

// Trả về:
"========== BÁO CÁO LỚP 10A1 ==========
Tổng số học sinh: 3
Điểm trung bình lớp: 7.0
Học sinh giỏi: 0 (0%)
Học sinh khá: 2 (67%)
Học sinh trung bình: 1 (33%)
Học sinh yếu: 0 (0%)
Học sinh cao điểm nhất: Nguyen Van A (8.0)"

� Xem đáp án

💡 Lời giải chi tiết

Hàm 1: calculateStudentAverage(student)

function calculateStudentAverage(student) {
  const subjects = student.subjects;
  const grades = Object.values(subjects);
  const sum = grades.reduce((total, grade) => total + grade, 0);
  const average = sum / grades.length;
  return Math.round(average * 10) / 10; // Làm tròn 1 chữ số thập phân
}

Hàm 2: classifyStudent(average)

function classifyStudent(average) {
  if (average >= 8.5) return "Giỏi";
  if (average >= 7.0) return "Khá";
  if (average >= 5.5) return "Trung bình";
  return "Yếu";
}

Hàm 3: getStudentsByClass(students, className)

function getStudentsByClass(students, className) {
  return students
    .filter(student => student.class === className)
    .map(student => {
      const average = calculateStudentAverage(student);
      const classification = classifyStudent(average);
      return {
        ...student,
        average: average,
        classification: classification
      };
    });
}

Hàm 4: generateClassReport(students, className)

function generateClassReport(students, className) {
  const classStudents = getStudentsByClass(students, className);
  
  if (classStudents.length === 0) {
    return `Không tìm thấy học sinh trong lớp ${className}`;
  }
  
  const totalStudents = classStudents.length;
  const classAverage = classStudents.reduce((sum, student) => sum + student.average, 0) / totalStudents;
  
  // Đếm theo xếp loại
  const classifications = {
    "Giỏi": 0,
    "Khá": 0,
    "Trung bình": 0,
    "Yếu": 0
  };
  
  classStudents.forEach(student => {
    classifications[student.classification]++;
  });
  
  // Tìm học sinh cao điểm nhất
  const topStudent = classStudents.reduce((top, student) => 
    student.average > top.average ? student : top
  );
  
  return `========== BÁO CÁO LỚP ${className} ==========
Tổng số học sinh: ${totalStudents}
Điểm trung bình lớp: ${classAverage.toFixed(1)}
Học sinh giỏi: ${classifications["Giỏi"]} (${Math.round(classifications["Giỏi"]/totalStudents*100)}%)
Học sinh khá: ${classifications["Khá"]} (${Math.round(classifications["Khá"]/totalStudents*100)}%)
Học sinh trung bình: ${classifications["Trung bình"]} (${Math.round(classifications["Trung bình"]/totalStudents*100)}%)
Học sinh yếu: ${classifications["Yếu"]} (${Math.round(classifications["Yếu"]/totalStudents*100)}%)
Học sinh cao điểm nhất: ${topStudent.name} (${topStudent.average})`;
}

Cách sử dụng:

// Test với dữ liệu mẫu
const students = [
  { id: 1, name: "Nguyen Van A", class: "10A1", subjects: { math: 8, physics: 7, chemistry: 9 } },
  { id: 2, name: "Le Thi B", class: "10A1", subjects: { math: 6, physics: 8, chemistry: 7 } },
  { id: 3, name: "Tran Van C", class: "10A2", subjects: { math: 9, physics: 8, chemistry: 8 } },
  { id: 4, name: "Pham Thi D", class: "10A1", subjects: { math: 5, physics: 6, chemistry: 7 } }
];

// Test từng hàm
console.log(calculateStudentAverage(students[0])); // 8.0
console.log(classifyStudent(8.0)); // "Khá"
console.log(getStudentsByClass(students, "10A1"));
console.log(generateClassReport(students, "10A1"));

Bài Tập 5: Quản Lý Nhân Viên Công Ty

🎯 Mục tiêu

Tạo hệ thống quản lý nhân viên với các chức năng: tính lương, thống kê phòng ban, tìm kiếm.

📥 Dữ liệu mẫu

const employees = [
  { id: 1, name: "Nguyen Van A", department: "IT", position: "Developer", salary: 20000000, startDate: "2020-01-15" },
  { id: 2, name: "Le Thi B", department: "IT", position: "Tester", salary: 15000000, startDate: "2021-03-10" },
  { id: 3, name: "Tran Van C", department: "HR", position: "Manager", salary: 25000000, startDate: "2019-06-01" },
  { id: 4, name: "Pham Thi D", department: "Finance", position: "Accountant", salary: 18000000, startDate: "2022-01-20" }
];

const bonusRules = {
  "Manager": 0.2,      // 20% bonus
  "Developer": 0.15,   // 15% bonus
  "Tester": 0.1,       // 10% bonus
  "Accountant": 0.12   // 12% bonus
};

📤 Các hàm cần viết

🔧 Hàm 1: calculateTotalSalary(employee, bonusRules)

Nhiệm vụ: Tính tổng lương của nhân viên (lương cơ bản + bonus)

Input: Object employee, Object bonusRules

Output: Number - tổng lương

Ví dụ:

calculateTotalSalary(employees[0], bonusRules)
// Trả về: 23000000  (20000000 + 20000000 * 0.15)

🔧 Hàm 2: getEmployeesByDepartment(employees, department)

Nhiệm vụ: Lọc nhân viên theo phòng ban

Input: Array employees, String department

Output: Array các nhân viên thuộc phòng ban đó

Ví dụ:

getEmployeesByDepartment(employees, "IT")
// Trả về: [Nguyen Van A, Le Thi B]

🔧 Hàm 3: findHighestPaidEmployee(employees, bonusRules)

Nhiệm vụ: Tìm nhân viên có lương cao nhất (sử dụng hàm 1)

Input: Array employees, Object bonusRules

Output: Object nhân viên có lương cao nhất với thông tin lương

Ví dụ:

findHighestPaidEmployee(employees, bonusRules)
// Trả về: { 
//   employee: { id: 3, name: "Tran Van C", ... },
//   totalSalary: 30000000
// }

🔧 Hàm 4: generatePayrollReport(employees, bonusRules)

Nhiệm vụ: Tạo báo cáo bảng lương tổng hợp

Input: Array employees, Object bonusRules

Output: String - báo cáo bảng lương chi tiết

Ví dụ:

// Trả về:
"========== BÁO CÁO BẢNG LƯƠNG ==========
Tổng số nhân viên: 4
Tổng chi phí lương: 86,000,000đ
Lương trung bình: 21,500,000đ

PHÒNG BAN:
- IT: 2 nhân viên (38,000,000đ)
- HR: 1 nhân viên (30,000,000đ)
- Finance: 1 nhân viên (20,160,000đ)

Nhân viên lương cao nhất: Tran Van C (30,000,000đ)"

� Xem đáp án

💡 Lời giải chi tiết

Hàm 1: calculateTotalSalary(employee, bonusRules)

function calculateTotalSalary(employee, bonusRules) {
  const bonusRate = bonusRules[employee.position] || 0;
  const bonus = employee.salary * bonusRate;
  return employee.salary + bonus;
}

Hàm 2: getEmployeesByDepartment(employees, department)

function getEmployeesByDepartment(employees, department) {
  return employees.filter(employee => employee.department === department);
}

Hàm 3: findHighestPaidEmployee(employees, bonusRules)

function findHighestPaidEmployee(employees, bonusRules) {
  let highestPaid = null;
  let maxSalary = 0;
  
  employees.forEach(employee => {
    const totalSalary = calculateTotalSalary(employee, bonusRules);
    if (totalSalary > maxSalary) {
      maxSalary = totalSalary;
      highestPaid = employee;
    }
  });
  
  return {
    employee: highestPaid,
    totalSalary: maxSalary
  };
}

Hàm 4: generatePayrollReport(employees, bonusRules)

function generatePayrollReport(employees, bonusRules) {
  const totalEmployees = employees.length;
  
  // Tính tổng chi phí lương
  const totalPayroll = employees.reduce((sum, employee) => {
    return sum + calculateTotalSalary(employee, bonusRules);
  }, 0);
  
  const averageSalary = totalPayroll / totalEmployees;
  
  // Thống kê theo phòng ban
  const departmentStats = {};
  employees.forEach(employee => {
    const dept = employee.department;
    const totalSalary = calculateTotalSalary(employee, bonusRules);
    
    if (!departmentStats[dept]) {
      departmentStats[dept] = { count: 0, totalSalary: 0 };
    }
    departmentStats[dept].count++;
    departmentStats[dept].totalSalary += totalSalary;
  });
  
  // Tìm nhân viên lương cao nhất
  const highestPaid = findHighestPaidEmployee(employees, bonusRules);
  
  // Tạo báo cáo
  let report = `========== BÁO CÁO BẢNG LƯƠNG ==========
Tổng số nhân viên: ${totalEmployees}
Tổng chi phí lương: ${totalPayroll.toLocaleString()}đ
Lương trung bình: ${Math.round(averageSalary).toLocaleString()}đ

PHÒNG BAN:`;
  
  Object.keys(departmentStats).forEach(dept => {
    const stats = departmentStats[dept];
    report += `\n- ${dept}: ${stats.count} nhân viên (${stats.totalSalary.toLocaleString()}đ)`;
  });
  
  report += `\n\nNhân viên lương cao nhất: ${highestPaid.employee.name} (${highestPaid.totalSalary.toLocaleString()}đ)`;
  
  return report;
}

Cách sử dụng:

// Test với dữ liệu mẫu
const employees = [
  { id: 1, name: "Nguyen Van A", department: "IT", position: "Developer", salary: 20000000, startDate: "2020-01-15" },
  { id: 2, name: "Le Thi B", department: "IT", position: "Tester", salary: 15000000, startDate: "2021-03-10" },
  { id: 3, name: "Tran Van C", department: "HR", position: "Manager", salary: 25000000, startDate: "2019-06-01" },
  { id: 4, name: "Pham Thi D", department: "Finance", position: "Accountant", salary: 18000000, startDate: "2022-01-20" }
];

const bonusRules = {
  "Manager": 0.2,
  "Developer": 0.15,
  "Tester": 0.1,
  "Accountant": 0.12
};

// Test từng hàm
console.log(calculateTotalSalary(employees[0], bonusRules)); // 23000000
console.log(getEmployeesByDepartment(employees, "IT"));
console.log(findHighestPaidEmployee(employees, bonusRules));
console.log(generatePayrollReport(employees, bonusRules));

Bài Tập 6: Quản Lý Bán Hàng Siêu Thị

🎯 Mục tiêu

Tạo hệ thống bán hàng siêu thị với các chức năng: quản lý kho, tính tiền, thống kê doanh thu.

📥 Dữ liệu mẫu

const products = [
  { id: 1, name: "Sữa tươi", price: 25000, category: "Dairy", stock: 100, supplier: "Vinamilk" },
  { id: 2, name: "Bánh mì", price: 15000, category: "Bakery", stock: 50, supplier: "Kinh Do" },
  { id: 3, name: "Táo", price: 30000, category: "Fruit", stock: 80, supplier: "Dalat Farm" },
  { id: 4, name: "Thịt bò", price: 200000, category: "Meat", stock: 20, supplier: "CP Foods" }
];

const sales = [
  { id: 1, productId: 1, quantity: 5, saleDate: "2024-01-15", customerId: 1 },
  { id: 2, productId: 2, quantity: 3, saleDate: "2024-01-15", customerId: 2 },
  { id: 3, productId: 3, quantity: 10, saleDate: "2024-01-16", customerId: 1 }
];

📤 Các hàm cần viết

🔧 Hàm 1: calculateSaleTotal(products, sale)

Nhiệm vụ: Tính tổng tiền cho một lần bán hàng

Input: Array products, Object sale

Output: Number - tổng tiền

Ví dụ:

calculateSaleTotal(products, sales[0])
// Trả về: 125000  (25000 * 5)

🔧 Hàm 2: updateProductStock(products, productId, quantitySold)

Nhiệm vụ: Cập nhật số lượng tồn kho sau khi bán

Input: Array products, Number productId, Number quantitySold

Output: Object {success: boolean, message: string, updatedProduct: object}

Ví dụ:

updateProductStock(products, 1, 5)
// Trả về: {
//   success: true,
//   message: "Cập nhật thành công",
//   updatedProduct: { id: 1, name: "Sữa tươi", stock: 95, ... }
// }

🔧 Hàm 3: getProductsByCategory(products, category)

Nhiệm vụ: Lấy danh sách sản phẩm theo thể loại

Input: Array products, String category

Output: Array các sản phẩm thuộc thể loại đó

Ví dụ:

getProductsByCategory(products, "Dairy")
// Trả về: [{ id: 1, name: "Sữa tươi", ... }]

🔧 Hàm 4: generateSalesReport(products, sales, date)

Nhiệm vụ: Tạo báo cáo doanh thu theo ngày (sử dụng hàm 1)

Input: Array products, Array sales, String date

Output: String - báo cáo doanh thu chi tiết

Ví dụ:

// Trả về:
"========== BÁO CÁO DOANH THU NGÀY 15/01/2024 ==========
Tổng số giao dịch: 2
Tổng doanh thu: 170,000đ

CHI TIẾT BÁN HÀNG:
- Sữa tươi: 5 x 25,000đ = 125,000đ
- Bánh mì: 3 x 15,000đ = 45,000đ

SẢN PHẨM BÁN CHẠY: Sữa tươi (5 sản phẩm)"

🔓 Xem đáp án

💡 Lời giải chi tiết

Hàm 1: calculateSaleTotal(products, sale)

function calculateSaleTotal(products, sale) {
  const product = products.find(p => p.id === sale.productId);
  if (!product) return 0;
  return product.price * sale.quantity;
}

Hàm 2: updateProductStock(products, productId, quantitySold)

function updateProductStock(products, productId, quantitySold) {
  const product = products.find(p => p.id === productId);
  
  if (!product) {
    return {
      success: false,
      message: "Sản phẩm không tồn tại",
      updatedProduct: null
    };
  }
  
  if (product.stock < quantitySold) {
    return {
      success: false,
      message: "Không đủ hàng trong kho",
      updatedProduct: null
    };
  }
  
  product.stock -= quantitySold;
  
  return {
    success: true,
    message: "Cập nhật thành công",
    updatedProduct: product
  };
}

Hàm 3: getProductsByCategory(products, category)

function getProductsByCategory(products, category) {
  return products.filter(product => product.category === category);
}

Hàm 4: generateSalesReport(products, sales, date)

function generateSalesReport(products, sales, date) {
  // Lọc giao dịch theo ngày
  const dailySales = sales.filter(sale => sale.saleDate === date);
  
  if (dailySales.length === 0) {
    return `Không có giao dịch nào trong ngày ${date}`;
  }
  
  // Tính tổng doanh thu
  const totalRevenue = dailySales.reduce((sum, sale) => {
    return sum + calculateSaleTotal(products, sale);
  }, 0);
  
  // Tạo chi tiết bán hàng
  const salesDetails = {};
  dailySales.forEach(sale => {
    const product = products.find(p => p.id === sale.productId);
    if (product) {
      if (!salesDetails[product.name]) {
        salesDetails[product.name] = {
          quantity: 0,
          price: product.price,
          total: 0
        };
      }
      salesDetails[product.name].quantity += sale.quantity;
      salesDetails[product.name].total += calculateSaleTotal(products, sale);
    }
  });
  
  // Tìm sản phẩm bán chạy nhất
  const bestSelling = Object.keys(salesDetails).reduce((best, current) => {
    return salesDetails[current].quantity > salesDetails[best].quantity ? current : best;
  });
  
  // Tạo báo cáo
  let report = `========== BÁO CÁO DOANH THU NGÀY ${date} ==========
Tổng số giao dịch: ${dailySales.length}
Tổng doanh thu: ${totalRevenue.toLocaleString()}đ

CHI TIẾT BÁN HÀNG:`;
  
  Object.keys(salesDetails).forEach(productName => {
    const details = salesDetails[productName];
    report += `\n- ${productName}: ${details.quantity} x ${details.price.toLocaleString()}đ = ${details.total.toLocaleString()}đ`;
  });
  
  report += `\n\nSẢN PHẨM BÁN CHẠY: ${bestSelling} (${salesDetails[bestSelling].quantity} sản phẩm)`;
  
  return report;
}

Cách sử dụng:

// Test với dữ liệu mẫu
const products = [
  { id: 1, name: "Sữa tươi", price: 25000, category: "Dairy", stock: 100, supplier: "Vinamilk" },
  { id: 2, name: "Bánh mì", price: 15000, category: "Bakery", stock: 50, supplier: "Kinh Do" },
  { id: 3, name: "Táo", price: 30000, category: "Fruit", stock: 80, supplier: "Dalat Farm" },
  { id: 4, name: "Thịt bò", price: 200000, category: "Meat", stock: 20, supplier: "CP Foods" }
];

const sales = [
  { id: 1, productId: 1, quantity: 5, saleDate: "2024-01-15", customerId: 1 },
  { id: 2, productId: 2, quantity: 3, saleDate: "2024-01-15", customerId: 2 },
  { id: 3, productId: 3, quantity: 10, saleDate: "2024-01-16", customerId: 1 }
];

// Test từng hàm
console.log(calculateSaleTotal(products, sales[0])); // 125000
console.log(updateProductStock(products, 1, 5));
console.log(getProductsByCategory(products, "Dairy"));
console.log(generateSalesReport(products, sales, "2024-01-15"));